package com.imyuanma.qingyun.ums.service.impl;

import com.imyuanma.qingyun.common.exception.ParamException;
import com.imyuanma.qingyun.common.model.PageQuery;
import com.imyuanma.qingyun.common.util.AssertUtil;
import com.imyuanma.qingyun.common.util.StringUtil;
import com.imyuanma.qingyun.interfaces.monitor.annotation.Trace;
import com.imyuanma.qingyun.ums.dao.IUmsOrgDao;
import com.imyuanma.qingyun.ums.model.UmsOrg;
import com.imyuanma.qingyun.ums.model.enums.EUmsOrgTypeEnum;
import com.imyuanma.qingyun.ums.service.IUmsOrgService;
import com.imyuanma.qingyun.ums.util.UmsConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 组织机构服务
 *
 * @author YuanMaKeJi
 * @date 2022-10-08 15:19:19
 */
@Slf4j
@Service
public class UmsOrgServiceImpl implements IUmsOrgService {

    /**
     * 组织机构dao
     */
    @Autowired
    private IUmsOrgDao umsOrgDao;

    /**
     * 列表查询
     *
     * @param umsOrg 查询条件
     * @return
     */
    @Trace("查询组织机构列表")
    @Override
    public List<UmsOrg> getList(UmsOrg umsOrg) {
        return umsOrgDao.getList(umsOrg);
    }

    /**
     * 分页查询
     *
     * @param umsOrg    查询条件
     * @param pageQuery 分页参数
     * @return
     */
    @Trace("分页查询组织机构")
    @Override
    public List<UmsOrg> getPage(UmsOrg umsOrg, PageQuery pageQuery) {
        return umsOrgDao.getList(umsOrg, pageQuery);
    }

    /**
     * 统计数量
     *
     * @param umsOrg 查询条件
     * @return
     */
    @Trace("统计组织机构数量")
    @Override
    public int count(UmsOrg umsOrg) {
        return umsOrgDao.count(umsOrg);
    }

    /**
     * 主键查询
     *
     * @param id 主键
     * @return
     */
    @Trace("根据主键查询组织机构")
    @Override
    public UmsOrg get(Long id) {
        return umsOrgDao.get(id);
    }

    /**
     * 主键批量查询
     *
     * @param list 主键集合
     * @return
     */
    @Trace("根据主键批量查询组织机构")
    @Override
    public List<UmsOrg> getListByIds(List<Long> list) {
        return umsOrgDao.getListByIds(list);
    }

    /**
     * 插入
     *
     * @param umsOrg 参数
     * @return
     */
    @Trace("插入组织机构")
    @Override
    public int insert(UmsOrg umsOrg) {
        return umsOrgDao.insert(umsOrg);
    }

    /**
     * 选择性插入
     *
     * @param umsOrg 参数
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    @Trace("选择性插入组织机构")
    @Override
    public int insertSelective(UmsOrg umsOrg) {
        AssertUtil.notBlank(umsOrg.getCode(), "组织机构编号必填");
        AssertUtil.notBlank(umsOrg.getName(), "组织机构名称必填");
        AssertUtil.notNull(umsOrg.getType(), "组织机构类型必填");
        AssertUtil.inEnums(umsOrg.getType(), Arrays.stream(EUmsOrgTypeEnum.values()).map(EUmsOrgTypeEnum::getCode).collect(Collectors.toList()), "组织机构类型非法");
        // 上级节点修正
        if (umsOrg.getParentId() == null || umsOrg.getParentId() == 0L) {
            umsOrg.setParentId(UmsConstants.ROOT_ORG_ID);
        }
        // 别名修正
        if (StringUtil.isBlank(umsOrg.getAlias())) {
            umsOrg.setAlias(umsOrg.getName());
        }
        // 组织编号唯一性验证
        UmsOrg countQuery = new UmsOrg();
        countQuery.setCode(umsOrg.getCode());
        int count = this.count(umsOrg);
        if (count > 0) {
            log.warn("[选择性插入组织机构] 根据code={}查询组织机构数量={}", umsOrg.getCode(), count);
            throw new ParamException("组织机构编号不允许重复");
        }

        // 查询上级节点
        UmsOrg parent = this.get(umsOrg.getParentId());
        if (parent == null) {
            log.warn("[选择性插入组织机构] 新增失败:查询上级节点不存在,上级id={}", umsOrg.getParentId());
            throw new ParamException("上级组织不存在");
        }
        // 设置所属单位
        if (EUmsOrgTypeEnum.CODE_10.getCode().equals(umsOrg.getType())) {
            // 如果自身是单位类型节点, 则所属单位是自己, 设置个无效值, 等新增完成后更新(因为只有新增成功后才能拿到自身id)
            umsOrg.setCompanyId(0L);
        } else {
            // 其他类型的节点, 所属单位就是上级节点所属的单位
            umsOrg.setCompanyId(parent.getCompanyId());
        }
        // 计算id全路径(插入后更新), name全路径
        umsOrg.setWholeId(parent.getWholeId() + "/?");
        umsOrg.setWholeName(parent.getWholeName() + "/" + umsOrg.getName());

        // 插入节点
        umsOrgDao.insertSelective(umsOrg);


        // 插入后更新相关字段
        UmsOrg update = new UmsOrg();
        update.setId(umsOrg.getId());
        // 更新所属单位
        if (EUmsOrgTypeEnum.CODE_10.getCode().equals(umsOrg.getType())) {
            update.setCompanyId(umsOrg.getId());
        }
        // 更新id全路径
        update.setWholeId(parent.getWholeId() + "/" + umsOrg.getId());
        // 更新
        umsOrgDao.updateSelective(update);

        return 1;
    }

    /**
     * 批量插入
     *
     * @param list 参数
     * @return
     */
    @Trace("批量插入组织机构")
    @Override
    public int batchInsert(List<UmsOrg> list) {
        return umsOrgDao.batchInsert(list);
    }

    /**
     * 批量选择性插入
     *
     * @param list 参数
     * @return
     */
    @Trace("批量选择性插入组织机构")
    @Override
    public int batchInsertSelective(List<UmsOrg> list) {
        return umsOrgDao.batchInsertSelective(list);
    }

    /**
     * 修改
     *
     * @param umsOrg 参数
     * @return
     */
    @Trace("修改组织机构")
    @Override
    public int update(UmsOrg umsOrg) {
        return umsOrgDao.update(umsOrg);
    }

    /**
     * 选择性修改
     *
     * @param umsOrg 参数
     * @return
     */
    @Trace("选择性修改组织机构")
    @Override
    public int updateSelective(UmsOrg umsOrg) {
        return umsOrgDao.updateSelective(umsOrg);
    }

    /**
     * 删除
     *
     * @param id 主键
     * @return
     */
    @Trace("删除组织机构")
    @Override
    public int delete(Long id) {
        return umsOrgDao.delete(id);
    }

    /**
     * 批量删除
     *
     * @param list 主键集合
     * @return
     */
    @Trace("批量删除组织机构")
    @Override
    public int batchDelete(List<Long> list) {
        return umsOrgDao.batchDelete(list);
    }

    /**
     * 条件删除(默认和getList方法的条件相同)
     *
     * @param umsOrg 参数
     * @return
     */
    @Trace("根据条件删除组织机构")
    @Override
    public int deleteByCondition(UmsOrg umsOrg) {
        return umsOrgDao.deleteByCondition(umsOrg);
    }

}
